# coding=utf-8
import logging
from datetime import datetime, timedelta
from common.utils.decorator import sql_wrapper
from common.utils.db import list_object, get, upsert, list_export_object, generate_filter
from common.order.model import Order, NOTIFY_STATUS, PAY_STATUS
from common.bank_record.model import BankRecord
from common.utils import id_generator
from common.utils import exceptions as err
from common import orm
from sqlalchemy import func

_LOGGER = logging.getLogger('hydra')


@sql_wrapper
def get_order(id):
    return get(Order, id)


@sql_wrapper
def upsert_order(info, id=None):
    return upsert(Order, info, id)


@sql_wrapper
def list_order(query_dct):
    return list_object(query_dct, Order)


@sql_wrapper
def list_order_join(query_dct):
    x = orm.session.query(Order).join(BankRecord, (Order.id == BankRecord.order_id)) \
        .filter(BankRecord.status == 1) \
        .filter(generate_filter(query_dct, Order))
    return x


@sql_wrapper
def get_order_overview(parsed_dct):


    query = orm.session.query(func.sum(Order.total_fee))
    query = query.filter(generate_filter(parsed_dct, Order))
    total_fee = query.scalar()

    query1 = orm.session.query(func.sum(Order.real_amount))
    query1 = query1.filter(generate_filter(parsed_dct, Order))
    real_amount = query1.scalar()

    exact_amount_succ = query1.filter(Order.status == PAY_STATUS.SUCC).scalar()

    exact_amount_manual = orm.session.query(func.sum(Order.real_amount)) \
                    .filter(generate_filter(parsed_dct, Order)) \
                    .filter(Order.status == PAY_STATUS.MANUAL_SUCC).scalar() 

    exact_amount_succ = exact_amount_succ if exact_amount_succ else 0
    exact_amount_manual = exact_amount_manual if exact_amount_manual else 0
    exact_amount = exact_amount_manual + exact_amount_succ
    
    success_rate1 = orm.session.query(func.count(Order)).filter(generate_filter(parsed_dct, Order)) \
                   .filter(Order.status == PAY_STATUS.MANUAL_SUCC).all()

    success_rate2 = orm.session.query(func.count(Order)).filter(generate_filter(parsed_dct, Order)) \
                   .filter(Order.status == PAY_STATUS.SUCC).all()

    success_rate = success_rate1[0][0] + success_rate2[0][0]
    success_rate = success_rate + 0.00
    return total_fee, real_amount, exact_amount, success_rate, success_rate1[0][0]


@sql_wrapper
def list_export_order(query_dct):
    return list_export_object(query_dct, Order)

@sql_wrapper
def add_notify_success(pay_id):
    order = Order.query.filter(Order.id == pay_id).with_lockmode('update').first()
    order.notify_status = NOTIFY_STATUS.SUCC
    order.notify_count += 1
    order.notified_at = datetime.utcnow()
    order.save()
    return order


@sql_wrapper
def add_notify_fail(pay_id):
    order = Order.query.filter(Order.id == pay_id).with_lockmode('update').first()
    order.notify_status = NOTIFY_STATUS.FAIL
    order.notify_count += 1
    order.notified_at = datetime.utcnow()
    order.save()
    return order


@sql_wrapper
def create_order(data, bankcard_name, bankcard_num, real_amount):
    try:
        order = Order()
        order.id = id_generator.generate_long_id('hydra')
        order.mch_id = data['mch_id']
        order.bankcard_name = bankcard_name
        order.bankcard_num = bankcard_num
        order.out_trade_no = data['out_trade_no']
        order.status = PAY_STATUS.READY
        order.body = data['body']
        order.total_fee = data['total_fee']
        order.real_amount = real_amount
        order.notify_url = data['notify_url']
        order.mch_create_ip = data['mch_create_ip']
        order.sign = data['sign']
        order.extra = data.get('extra')
        order.notify_status = NOTIFY_STATUS.READY
        order.user_id = data.get('user_id')
        order.pay_type = data['pay_type']
        order.save()
        return order
    except Exception as e:
        _LOGGER.exception('create_order error, %s', e)
        raise err.DataError()


@sql_wrapper
def add_order_success(record_id, bankcard_name, real_amount):
    pay = Order.query.filter(Order.bankcard_name == bankcard_name).filter(
        Order.status == PAY_STATUS.READY).filter(Order.real_amount == real_amount).order_by(
        Order.created_at.desc()).first()
    if pay is None:
        return None, None
    pay.status = PAY_STATUS.SUCC
    pay.real_amount = real_amount
    pay.record_id = record_id
    pay.payed_at = datetime.utcnow()
    pay.save()
    return pay.id, pay.total_fee


@sql_wrapper
def add_special_order_success(order_id, record_id, bankcard_name, real_amount, msg):
    pay = Order.query.filter(Order.id == order_id).filter(
        Order.status.in_([PAY_STATUS.READY, PAY_STATUS.OVERTIME])).filter(Order.bankcard_name == bankcard_name).first()
    if pay is None:
        raise err.ParamError(u'指定订单不存在')
    pay.status = PAY_STATUS.SUCC
    pay.real_amount = real_amount
    pay.total_fee = real_amount
    pay.record_id = record_id
    pay.payed_at = datetime.utcnow()
    pay.extend = msg
    pay.save()
    return True


@sql_wrapper
def get_mch_order(mch_id, out_trade_no):
    return Order.query.filter(Order.mch_id == mch_id).filter(
        Order.out_trade_no == out_trade_no).first()


@sql_wrapper
def get_card_late_order_status(card_name, minute_ago=15):
    ttt = datetime.utcnow() + timedelta(minutes=-minute_ago)
    total_count = Order.query.filter(Order.bankcard_name == card_name).filter(
        Order.created_at > ttt).count()
    success_count = Order.query.filter(Order.bankcard_name == card_name).filter(Order.status == PAY_STATUS.SUCC).filter(
        Order.created_at > ttt).count()
    return total_count, success_count


@sql_wrapper
def add_sms_order_success(sms_id, bankcard_name, real_amount):
    pay = Order.query.filter(Order.bankcard_name == bankcard_name).filter(
        Order.status == PAY_STATUS.READY).filter(Order.real_amount == real_amount).order_by(
        Order.created_at.desc()).first()
    if pay is None:
        return None, None
    pay.status = PAY_STATUS.SUCC
    pay.real_amount = real_amount
    pay.sms_id = sms_id
    pay.payed_at = datetime.utcnow()
    pay.save()
    return pay.id, pay.total_fee


@sql_wrapper
def get_notified_failed_orders():
    orders = Order.query.filter(
                Order.status.in_((PAY_STATUS.SUCC, PAY_STATUS.MANUAL_SUCC, PAY_STATUS.FAIL)), 
                Order.notify_status == NOTIFY_STATUS.FAIL,
                Order.notify_failed_retry < 2).all();

    return orders


@sql_wrapper
def modify_order_status_to_manual_success(order_id, operator):
    order = Order.query.filter(Order.id == order_id).first()
    if order is None:
        return
    order.status = PAY_STATUS.MANUAL_SUCC
    order.operator = operator
    order.save()
    return order
